#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include "LockGuard.hpp"
using namespace std;
const int defaultsize = 10;
template <class T>
class ringqueue {
    private :
    // P操作
    void P(sem_t *sem) {
        sem_wait(sem);
    }
    // V操作
    void  V(sem_t *sem) {
        sem_post(sem);
    }
    public :
    ringqueue(int size = defaultsize) 
        :_ringqueue(size)
        ,_size(size)
        ,_p_step(0)
        ,_c_step(0)
    {
        // 初始化信号量
        sem_init(&_space_sem, 0, size);
        sem_init(&_data_sem, 0, 0);

        // 初始化锁
        pthread_mutex_init(&_p_mutex, nullptr);
        pthread_mutex_init(&_c_mutex, nullptr);
    }

    void push(const T& in) {
        // 先申请空间
        P(&_space_sem);
        { // 临界区代码
            // 加锁
            LockGuard lock(&_p_mutex);
            _ringqueue[_p_step] = in;
            _p_step++;
            _p_step %= _size;
        }
        // 增加数据
        V(&_data_sem);
    }

    void Pop(T* out) {
        // 先申请数据
        P(&_data_sem);

        {
            // 加锁
            LockGuard lock(&_c_mutex);
            *out = _ringqueue[_c_step];
            _c_step++;
            _c_step %= _size;
        }

        // 增加空间
        V(&_space_sem);

    }



    ~ringqueue() {
        // 销毁信号量
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);

        // 销毁锁
        pthread_mutex_destroy(&_p_mutex);
        pthread_mutex_destroy(&_c_mutex);
    }
    private :
    vector<T> _ringqueue;
    int _size;
    int _p_step; // 生产者生产位置
    int _c_step; // 消费者消费位置
    sem_t _space_sem; // 空间信号量
    sem_t _data_sem; // 数据信号量

    pthread_mutex_t _p_mutex; // 生产者互斥锁
    pthread_mutex_t _c_mutex; // 消费者互斥锁

};